# -*- coding:utf-8 -*-

import re

# 1. match()


"""
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}',content)
'''
^ 匹配字符串开头, \s匹配空白字符或空格, \d匹配数字,3个\d匹配123, 再写1个\s匹配空格, \d{4} 代表匹配数字4次,也就是4个数字;  \w{10}匹配10个字母及下划线.
'''
print(result)
print(result.group())   # group方法可以输出匹配到的内容.
print(result.span())    # span方法可以输出匹配的范围
"""


## 匹配目标
"""
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld',content)
print(result)
print(result.group())  # 输出完整的匹配结果.
print(result.group(1))  # 输出第一个被()包围的匹配结果
print(result.span())
'''
使用()括号将想提取的子字符串括起来,()实际上标记了一个子表达式的开始和结束位置.被标记的每个子表达式会依次对应每一个分组,调用group()方法传入分组的索引即可获取提取的结果.
这里是将字符串中的1234567提取出来,将数字部分的正则表达式用()括起来,调用group(1) 获取匹配结果. 

group()会输出完整的匹配结果, group(1) 会输出第一个被()包围的匹配结果.假如有第二个还有第三个被()包围的匹配结果依次用group(2),group(3) 来获取.
'''
"""

##  通用匹配
"""
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$',content)
print(result)
print(result.group())   # group方法输出了匹配的全部字符串,
print(result.span())    # span方法输出的是整个字符串的长度.
"""

## 贪婪匹配
"""
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$',content)
print(result)
print(result.group())
print(result.group(1))  
# 以上结果会返回:
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex De
mo'>
Hello 1234567 World_This is a Regex Demo
7   只返回7这个数字,和我们需要的不符合. 这就是贪婪匹配造成的.这个时候需要使用非贪婪匹配了.
"""


## 非贪婪匹配
"""
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$',content)  # 转变为非贪婪匹配.
print(result)
print(result.group(1))
'''
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567 
贪婪匹配是尽可能匹配多的字符,非贪婪匹配就是尽可能匹配少的字符.当.*?匹配到Hello后面的空白字符时,再往后的字符就是数字了, \d+ 恰好可以匹配后面的数字. 

 在做匹配时,字符串中间尽量使用非贪婪匹配. 用.*?来代替.\* 
 注意: 如果匹配结果在字符串结尾, .*? 就可能匹配不到任何内容.
'''

cont = 'http://weibo.com/comment/kEraCN'
result1 = re.match('http.*?comment/(.*?)',cont)
result2 = re.match('http.*?comment/(.*)',cont)
print('result1',result1.group(1))
print('result2',result2.group(1))
'''
返回结果为:
result1
result2 kEraCN
.*? 没有匹配到任何结果, 而.* 则尽可能匹配多的内容. 得到匹配结果.
'''
"""

## 修饰符
"""
content = '''Hello 1234567 World_This 
is a Regex Demo'''
result = re.match('^He.*?(\d+).*?Demo$',content)
print(result.group(1))
'''
 报错: AttributeError: 'NoneType' object has no attribute 'group'
 因为.匹配的是除换行符之外的任意字符. 遇到换行符时, .*?就不能匹配,所以匹配失败. 添加一个修饰符re.S使.匹配包括换行符在内的所有字符.
 '''
 """


 ## 转义匹配
"""
content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com',content)
print(result)
print(result.group())  # 获取返回结果: (百度)www.baidu.com
"""

# 2. search()方法
"""
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo',content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())
"""


html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''

"""
'''
此时正则表达式可以以li开头, 然后寻找一个标志符active,中间的部分可以用.*?来匹配, 要提取singer这个属性值,还需要写入singer="(.*?)", 这里需要提取的部分用小括号括起来,这样可以用group()方法提取出来,它的两侧边界是双引号,然后还需要匹配a节点的文本,其中它的左边界是>, 右边界是</a>. 然后目标内容用(.*?) 来匹配,由于代码有换行,第三个参数传入修饰符re.S   .  由于需要获取的歌手和歌名已经用小括号包围,可以用group()方法获取.
'''
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)
if result:
    print(result.group(1),result.group(2))
    # 这正是class为active的li节点内部的超链接包含的歌手名和歌名



result1 = re.search('<li.*?singer="(.*?)">(.*?)</a>',html,re.S)
if result1:
    print(result1.group(1),result1.group(2))
    # 由于search()方法只返回第一个符合条件的匹配目标.
# 把active标签去掉后,从字符串开头开始搜索,此时符合条件的节点就变成了第二个li节点,后面的就不再匹配, 所以运行结果就变成第二个li节点中的内容.
# 添加修饰符re.S后,使得.*?可以匹配换行.所以含有换行的li节点被匹配到了.


# 去掉修饰符re.S后,是什么效果呢? 如下:
result2 = re.search('<li.*?singer="(.*?)">(.*?)</a>',html)
if result2:
    print(result2.group(1),result2.group(2))
# 结果变成了第四个li节点的内容,这是因为第二个和第三个li节点都包含了换行符,去掉re.S之后, .*?已经不能匹配换行符,所以正则表达式不会匹配到第二个和第三个li节点,而第四个li节点中不包含换行符, 所以成功匹配.

# 由于大部分html文本都包含了换行符,所以尽量加上re.S修饰符.
"""


# findall()方法
# findall该方法会搜索整个字符串,然后返回匹配正则表达式的所有内容.
"""
'''
示例采用上面的HTML文本, 获取所有a节点的超链接,歌手和歌名,返回结果为列表类型,需要遍历一下来依次获取每组内容.
'''
results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S)
print(results)

print('-----------------------')
print(type(results))
print('-----------------------')

for result in results:
    print(result)
    print('-----------------------')
    print(result[0],result[1],result[2])
# 返回的列表中的每个元素都是元组类型,用对应的索引依次取出即可.
# 获取第一个内容,用search()方法,当需要提取多个内容时,用findall()方法.
"""


# sub()方法
# 修改文本
"""
content = '54aK54yr5oiR54ix5L2g'
content = re.sub('\d+','',content)  # \d+匹配所有数字,将数字替换为空.
print(content)


# 获取所有li节点的歌名
results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html, re.S)
for resul in results:
    print(resul[1])


# 先用sub()方法将a节点去掉,只留下文本,再利用findall()提取.

html = re.sub('<a.*?>|</a>','',html)
print(html)

print('=======================')
results = re.findall('<li.*?>(.*?)</li>',html,re.S)
for result in results:
    print(result.strip())
# a节点经过sub()方法处理后就没有了,然后再通过findall()方法直接提取即可.
"""


# compile()
# compile()方法可以将正则字符串编译成正则表达式对象,也方便在后面的匹配中复用.

content1 = '2018-12-26 12:00'
content2 = '2018-12-27 12:55'
content3 = '2018-12-28 13:21'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern,'',content1)
result2 = re.sub(pattern,'',content2)
result3 = re.sub(pattern,'',content3)
print(result1,result2,result3)
'''
这里有3个日期,我们想分别将3个日期中的时间去掉,可以借助sub()方法.该方法的第一个参数是正则表达式,此时可借助compile()方法将正则表达式编译成一个正则表达式对象,以便复用.
'''





